import alphabet from "@/assets/alphabet.txt?raw";

export class Phonita {
	alphabet: Array<{
		latin: string;
		raw: string;
	}> = [];

	maxLatin() {
		return this.alphabet
			.map(({ latin }) => latin.length)
			.sort((a, b) => b - a)[0];
	}

	constructor(rawString?: string) {
		if (typeof rawString === "string") {
			this.loadFromRawString(rawString);
		}
	}

	appendLetters(raw: string, latin: string) {
		this.alphabet.push({
			latin,
			raw,
		});
	}

	loadFromRawString(rawString: string) {
		rawString
			.split("\n")
			.map((item) => item.trim())
			.filter(
				(item) =>
					item.length > 0 && !item.startsWith("//") && !item.startsWith("#")
			)
			.forEach((item) => {
				const [raw, latin] = item.split("=");
				if (latin) {
					this.appendLetters(raw, latin);
				}
			});
	}

	private hasKey(s: string) {
		return this.alphabet
			.map(({ latin }) => latin)
			.includes(s.toLocaleLowerCase());
	}

	private sliceMatcher(s: string) {
		let n = s.length;
		for (let i = n; i > 0; i--) {
			const slice = s.slice(0, i);
			for (const { raw, latin } of this.alphabet) {
				if (latin === slice) {
					return {
						val: raw,
						step: latin.length,
					};
				}
			}
		}

		return {
			val: s.slice(0, 1),
			step: 1,
		};
	}

	parseWord(s: string): string {
		let k = 0;
		let n = s.length;
		let l = this.maxLatin();
		s = s.toLocaleLowerCase();

		let ret = "";

		while (true) {
			const { val, step } = this.sliceMatcher(s.slice(k, k + l));

			k += step;
			ret += val;

			if (k >= n) {
				break;
			}
		}

		return ret;
	}

	parse(s: string) {
		if (s.length < 2) {
			return this.parseWord(s);
		}

		let list = s.split("");
		const box: Array<{ str: string; flag: boolean }> = [];

		let ret = "";
		let str = list[0];
		let flag = this.hasKey(str);
		for (const char of list.slice(1)) {
			const charFlag = this.hasKey(char);
			if (flag === charFlag) {
				str += char;
			} else {
				box.push({ flag, str });
				flag = charFlag;
				str = char;
			}
		}

		if (str.length > 0) {
			box.push({ flag, str });
		}

		for (const { flag, str } of box) {
			ret += flag ? this.parseWord(str) : str;
		}

		return ret;
	}

	static useInternalDictionary() {
		return new Phonita(alphabet);
	}
}
